/*
 * uart.c
 *
 * Created: 12/17/2012 12:17:26 PM
 *  Author: duerk@msoe.edu <Kevin Duer>
 *			zimmermane@msoe.edu <Evan Zimmerman>
 *			woottons@msoe.edu <Scott Wootton>
 *			
 * 
 * Purpose: This file has the functions used
 *          for the uart communication.
*/
#include "uart.h"
#include <avr/io.h>
#include <stdio.h>
#include <string.h>

volatile char RX_BUFF[BUFFER_SIZE];
volatile char* rxptr;
volatile char* charptr;

/* uart_init
 * 
 * Purpose: Setups up the uart for sending and receiving
 *          data.  The value for the URBRR is passed in
 *          and is assumed to only fit in the URBRRL.
 * Params: uint8_t ubrr_val - UBRR value
 * Returns: none
 */
void uart_init(uint8_t ubrr_val){
	// sets the desired baud rate
	UBRRL = ubrr_val;
	//set to zero
	UCSRA = 0;
	// enable transmit and receive
	UCSRB = (1<<TXEN)|(1<<RXEN);
	// synchronous operation, 8-bit char size
	UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
	// initialize pointers to 0
	rxptr = 0;
	charptr = 0;
	return;
}

/* uart_putc
 * 
 * Purpose: Puts the character into the UDR.  This will
 *          handle newlines and return characters
 *          as well.
 * Params: char c - character to be written to the UDR
 * Returns: none
 */
void uart_putc(char c){
	// wait here until the UDR is empty
	while(!(UCSRA&(1<<UDRE)));
	// add the char to the UDR
	UDR = c;
	// if the char is a newline, also send return
	if(c == '\n'){
		uart_putc('\r');
	}
	return;
}

/* uart_getc
 * 
 * Purpose: Gets the character for the UDR.  It will
 *          display the character back to the user.
 *          If the buffer is full it will send a beep.
 *          Return will reset the buffer and backspace
 *          will overwrite the previous character.
 * Params: none
 * Returns: char c - the character that was read
 */
char uart_getc(){
	char c;
	// if the start of a new line
	if(rxptr == 0){
		// initialize buffer write pointer to start of buffer
		for(charptr = RX_BUFF;;){
			// poll for new character
			while(!(UCSRA&(1<<RXC)));
			c = UDR;
			// if the char is a return, replace with newline,
			// increment the pointer, send the newline, reset
			// the recieve pointer and break the loop
			if(c == '\r'){
				c = '\n';
				*charptr = c;
				charptr++;
				uart_putc(c);
				rxptr = RX_BUFF;
				break;
			}
			// if char is printable
			else if((c >= ' ') && (c < 0x7F)){
				// if the buffer is full, send a beep to the terminal
				if(charptr == RX_BUFF + BUFFER_SIZE - 2){
					uart_putc('\a'); // beep
				}
				// otherwise set the char, increment the pointer, and send it
				else{
					*charptr = c;
					charptr++;
					uart_putc(c);
				}
			}
			// if backspace or delete
			else if((c == 0x08) || (c == 0x7F)){
				// if the write pointer is not at the start of the buffer
				if(charptr > RX_BUFF){
					uart_putc(0x08); // send backspace
					uart_putc(' ');  // send space to overwrite previous char
					uart_putc(0x08); // send backspace
					charptr--; // decrement the buffer write pointer
				}
			}
		}
	}
	// get the character
	c = *rxptr;
	// increment the read pointer
	rxptr++;
	// if the char was a newline, reset the read pointer to 0
	if(c == '\n'){
		rxptr = 0;
	}
	// return the char
	return c;
}
